package org.jpropelleralt.path;

import java.util.Iterator;

import org.jpropelleralt.box.Box;
import org.jpropelleralt.box.Boxes;
import org.jpropelleralt.ref.Ref;
import org.jpropelleralt.ref.impl.PathRef;

/**
 * Interface for extended {@link Iterator} that provides a sequence of
 * {@link Box}es via the normal {@link Iterator} interface, then
 * provides one final {@link Ref} containing a value of type T
 * 
 * These {@link Boxes} represent EVERY step in a path from a root (the
 * first returned {@link Box}) to the destination (the {@link Ref} returned
 * by {@link #destination()} after the {@link Iterator} has been completely
 * iterated).
 * 
 * "EVERY" step implies that if we have consider the element A at index n of the iteration,
 * we know that the element B at index n+1 will be directly reachable from A. That is,
 * B will be part of the "shallow" data of A. If the path changes such that element n
 * of the iteration is still the same instance A, but element n+1 is different, this
 * ALWAYS implies that A has had a shallow change. In fact this is relied on by optimisations
 * of users of {@link PathIterator}.
 * 
 * The {@link Ref} returned by {@link #destination()} is essentially the last element of
 * the iteration - hence the requirement for steps leading to directly reachable data
 * applies to it as well. So to use the same terminology as above, if A is the last 
 * element returned by the {@link Iterator} interface, B is the {@link Ref} returned 
 * by {@link #destination()}. The instance returned by {@link #destination()} will change
 * only if the last element returned by the {@link Iterator} interface has a shallow change.
 * 
 * The last step of the path (returned by {@link #destination()}) is always a {@link Ref}, 
 * and that {@link Ref} can then be mirrored by a {@link PathRef} using this {@link PathIterator}.
 * 
 * The path does NOT need to always start from the same {@link Box} each time it is iterated, 
 * however it normally will. It
 * MUST ensure that the set of iterated {@link Box}es, including the {@link #destination()}, is
 * such that if the final reached destination and its value change, there MUST be a shallow change to
 * at least one element of the iterated set. Again this is relied on by users of the {@link PathIterator}
 * for optimisation. This explains why the iterator will generally start from a fixed "root" box, and
 * then apply the same "rules" to iterate from this fixed starting position.
 * 
 * @param <T>		The type of value in the final {@link Ref}
 */
public interface PathIterator<T> extends Iterator<Box>{

	/**
	 * Get the final {@link Ref} in the iteration - this is only available AFTER
	 * the last element has been returned by the {@link Iterator} interface.
	 * In other words - you should iterate over all the {@link Box}es
	 * returned by {@link Iterator#next()}, then use this {@link Ref} as the
	 * final element.
	 * 
	 * @return			The destination at the end of the path
	 */
	public Ref<T> destination();
	
}